/**
 * 
 */
package xalan.filesearch.service;

import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import xalan.filesearch.model.Catalogue;
import xalan.filesearch.model.Tag;
import xalan.filesearch.filter.Filter;
import xalan.filesearch.model.FileDesc;

/** 
 * <!-- begin-UML-doc -->
 * <!-- end-UML-doc -->
 * @author Piotrek
 * @generated "UML to Java (com.ibm.xtools.transform.uml2.java5.internal.UML2JavaTransform)"
 */
public class CatalogueServiceImpl implements CatalogueService {
	/** 
	 * <!-- begin-UML-doc -->
	 * <!-- end-UML-doc -->
	 * @generated "UML to Java (com.ibm.xtools.transform.uml2.java5.internal.UML2JavaTransform)"
	 */
	private Set<Catalogue> catalogues;

	/** 
	 * <!-- begin-UML-doc -->
	 * <!-- end-UML-doc -->
	 * @generated "UML to Java (com.ibm.xtools.transform.uml2.java5.internal.UML2JavaTransform)"
	 */
	private XMLMarshaller marshaller;
	
	private Map<String, Tag> allTags;
	
	private Map<Tag, Integer> tagNumberOfOccurences;
	/** 
	 * /* (non-Javadoc)
	 *  * @see CatalogueService#createCatalogue(String path)
	 * 
	 * @generated "UML to Java (com.ibm.xtools.transform.uml2.java5.internal.UML2JavaTransform)"
	 */
	public Catalogue createCatalogue(String path) {
		// begin-user-code
		if (isPathValid(path)) {
			Catalogue c = new Catalogue();
			c.setPath(path);
			catalogues.add(c);
			refreshCatalogue(c);
			return c;
		}
		return null;
		// end-user-code
	}

	/** 
	 * /* (non-Javadoc)
	 *  * @see CatalogueService#isPathValid(String path)
	 * 
	 * @generated "UML to Java (com.ibm.xtools.transform.uml2.java5.internal.UML2JavaTransform)"
	 */
	public boolean isPathValid(String path) {
		// begin-user-code
		for (Catalogue c : catalogues) {
			if (c.getPath().equals(path)) {
				return false;
			}
		}
		File f = new File(path);
		return f.exists();
		// end-user-code
	}

	/** 
	 * /* (non-Javadoc)
	 *  * @see CatalogueService#getCatalogues()
	 * 
	 * @generated "UML to Java (com.ibm.xtools.transform.uml2.java5.internal.UML2JavaTransform)"
	 */
	public Set<Catalogue> getCatalogues() {
		// begin-user-code
		return catalogues;
		// end-user-code
	}

	/** 
	 * /* (non-Javadoc)
	 *  * @see CatalogueService#refreshCatalogue(Catalogue catalogue)
	 * 
	 * @generated "UML to Java (com.ibm.xtools.transform.uml2.java5.internal.UML2JavaTransform)"
	 */
	public void refreshCatalogue(Catalogue catalogue) {
		// begin-user-code
		List<String> allFiles = listFiles(new File(catalogue.getPath()));
		for (String f : allFiles) {
			boolean fileExists = false;
			for (FileDesc fd : catalogue.getFiles()) {
				if (f.equals(fd.getPath())) {
					fileExists = true;
				}
			}

			if (!fileExists) {
				FileDesc newFileDesc = new FileDesc();
				newFileDesc.setPath(f);
				catalogue.add(newFileDesc);
			}
		}

		for (FileDesc fd : catalogue.getFiles()) {
			boolean fileExists = false;
			for (String f : allFiles) {
				if (f.equals(fd.getPath())) {
					fileExists = true;
				}
			}

			if (!fileExists) {
				catalogue.remove(fd);
			}
		}
		// end-user-code
	}

	/** 
	 * /* (non-Javadoc)
	 *  * @see CatalogueService#saveCatalogues()
	 * 
	 * @generated "UML to Java (com.ibm.xtools.transform.uml2.java5.internal.UML2JavaTransform)"
	 */
	public void saveCatalogues() {
		// begin-user-code
		marshaller.serialize(catalogues);
		// end-user-code
	}

	/** 
	 * /* (non-Javadoc)
	 *  * @see CatalogueService#loadCatalogues()
	 * 
	 * @generated "UML to Java (com.ibm.xtools.transform.uml2.java5.internal.UML2JavaTransform)"
	 */
	public void loadCatalogues() {
		// begin-user-code
		catalogues = marshaller.deserialize();
		refreshTags();
		// end-user-code
	}

	/** 
	 * /* (non-Javadoc)
	 *  * @see CatalogueService#search(Filter Filter)
	 * 
	 * @generated "UML to Java (com.ibm.xtools.transform.uml2.java5.internal.UML2JavaTransform)"
	 */
	public Set<FileDesc> search(Filter filter) {
		// begin-user-code
		Set<FileDesc> result = new HashSet<FileDesc>();
		for(Catalogue c: catalogues) {
			for(FileDesc f: c.getFiles()) {
				if(filter.matches(f)) {
					result.add(f);
				}
			}
		}
		return result;
		// end-user-code
	}

	public CatalogueServiceImpl() {
		this.catalogues = new HashSet<Catalogue>();
		this.allTags = new HashMap<String, Tag>();
		this.tagNumberOfOccurences = new HashMap<Tag, Integer>();
	}

	protected List<String> listFiles(File file) {
		List<String> result = new LinkedList<String>();

		if (!file.isHidden()) {
			if (file.isDirectory()) {
				for (File f : file.listFiles()) {
					result.addAll(listFiles(f));
				}
			} else {
				result.add(file.getAbsolutePath());
			}
		}

		return result;
	}

	public void setMarshaller(XMLMarshaller marshaller) {
		this.marshaller = marshaller;
	}

	public Collection<Tag> getTags() {
		return allTags.values();
	}

	public Tag getTagByName(String tagName) {
		return allTags.get(tagName);
	}

	public void updateFile(FileDesc file, String newDescription, Set<Tag> newTags) {
		refreshTags(file.getTags(), newTags);
		file.setDescription(newDescription);
		file.getTags().clear();
		file.getTags().addAll(newTags);
	}
	
	protected void refreshTags() {
		allTags.clear();
		tagNumberOfOccurences.clear();
		
		for(Catalogue c: catalogues) {
			for(FileDesc f: c.getFiles()) {
				for(Tag t: f.getTags()) {
					Integer n = 0;
					if(tagNumberOfOccurences.containsKey(t)) {
						n = tagNumberOfOccurences.get(t);
						n++;
					}
					tagNumberOfOccurences.put(t, n);
					
					allTags.put(t.getName(), t);
				}
			}
		}
	}
	
	protected void refreshTags(Set<Tag> tagsToRemove, Set<Tag> tagsToAdd) {
		for(Tag t: tagsToRemove) {
			Integer n = tagNumberOfOccurences.get(t);
			if(n == 1) {
				allTags.remove(t);
				tagNumberOfOccurences.remove(t);
			}
		}
		
		for(Tag t: tagsToAdd) {
			Integer n = tagNumberOfOccurences.get(t);
			if(n == null) {
				allTags.put(t.getName(), t);
				tagNumberOfOccurences.put(t, 1);
			}
			else {
				tagNumberOfOccurences.put(t, n + 1);
			}
		}
	}
}